package com.jeff.work;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Scheduler {
    List<MyProcess> myProcesses;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
    public Scheduler() {
        this.myProcesses = new ArrayList<>();
    }

    public void addProcess(MyProcess myProcess) {
        myProcesses.add(myProcess);
    }

    /**
     * 按最高优先级优先调度算法模拟进程调度。
     * 这种算法首先选择优先级最高的进程进行执行，直到该进程完成或被暂停。
     * 然后选择下一个优先级最高的进程，以此类推。
     * 这个方法首先将所有进程状态设置为等待，然后根据优先级对进程进行排序。
     * 接下来，为每个进程计算开始时间和完成时间，并更新其状态为运行。
     * 最后，将所有进程的状态设置为完成。
     */
    public void highestPriorityFirst() {
        System.out.println("最高优先数优先调度算法:");
        // 重置所有进程状态为等待，以便开始新的调度周期
        //重置所有进程状态为 wait ,便于测试
        for (MyProcess process : myProcesses) {
            process.setStatus("wait");
        }

        // 根据优先级对进程进行降序排序，以便优先处理优先值高的进程
        myProcesses.sort(Comparator.comparingInt(MyProcess::getPriority).reversed());

        // 获取当前时间，用于计算进程的开始时间和完成时间
        LocalDateTime currentTime = LocalDateTime.now();

        // 遍历进程列表，计算每个进程的开始时间和完成时间，并更新其状态为运行
        for (MyProcess process : myProcesses) {
            System.out.println("当前进程: " + process.getName() + " 当前状态: "+ process.getStatus());

            // 计算进程的开始时间，并根据开始时间和执行时间长度计算完成时间
            process.setStartTime(currentTime.plusMinutes(process.getArrivalTime()));
            process.setFinishTime(process.getStartTime().plusMinutes(process.getBurstTime()+process.getWaitingTime()));
            process.setStatus("run");
            System.out.println("进程名: " + process.getName()
                    + " 优先级: " + process.getPriority()
                    + " 提交时间: " + process.getArrivalTime()
                    + " 运行时间: " + process.getBurstTime()
                    + " 开始时间: " + process.getStartTime().format(formatter)
                    + " 完成时间: " + process.getFinishTime().format(formatter)
                    + " 状态: " + process.getStatus());
            currentTime = process.getFinishTime();
        }

        // 将所有进程的状态设置为完成，表示调度过程结束
        for (MyProcess process : myProcesses) {
            process.setStatus("finish");
            System.out.println("进程名: " + process.getName() + " 状态: " + process.getStatus());
        }
    }


    /**
     * 实现先来先服务调度算法。
     * 这种调度算法按照进程到达的顺序来调度进程。
     * 首先，将所有进程的状态设置为"wait"，表示它们都在等待调度。
     * 然后，依次处理每个进程，设置其开始时间和完成时间，并更新其状态为"finish"。
     * 在处理过程中，打印出相关的信息，包括进程名、到达时间、运行时间、开始时间和完成时间。
     */
    public void firstComeFirstServe() {
        // 初始化所有进程状态为等待
        //重置所有进程状态为 wait ,便于测试
        for (MyProcess process : myProcesses) {
            process.setStatus("wait");
        }

        // 打印调度算法名称
        System.out.println("先来先服务调度算法:");
        // 获取当前时间作为调度开始时间
        LocalDateTime currentTime = LocalDateTime.now();
        myProcesses.sort(Comparator.comparingInt(MyProcess::getArrivalTime));

        // 遍历所有进程，进行调度处理
        for (MyProcess process : myProcesses) {
            // 打印当前进程的状态信息
            System.out.println("当前进程: " + process.getName() + " 当前状态: "+ process.getStatus());
            // 设置进程的开始时间为当前时间加上其到达时间
            process.setStartTime(currentTime.plusMinutes(process.getArrivalTime()));
            // 设置进程的完成时间为开始时间加上其执行时间和等待时间
            process.setFinishTime(process.getStartTime().plusMinutes(process.getBurstTime()+process.getWaitingTime()));
            // 打印进程的详细信息，包括进程名、到达时间、运行时间、开始时间和完成时间
            System.out.println("进程名: " + process.getName()
                    + " 提交时间: " + process.getArrivalTime()
                    + " 运行时间: " + process.getBurstTime()
                    + " 开始时间: " + process.getStartTime().format(formatter)
                    + " 完成时间: " + process.getFinishTime().format(formatter));
            // 更新进程状态为完成
            process.setStatus("finish");
            currentTime = process.getFinishTime();
            // 再次打印当前进程的状态信息
            System.out.println("当前进程: " + process.getName() + " 当前状态: "+ process.getStatus());
        }

    }


    /**
     * 实现时间片轮转调度算法。
     * @param timeSlice 每个进程的时间片大小。
     */
    public void roundRobin(int timeSlice) {
        // 初始化所有进程状态为等待
        //重置所有进程状态为 wait ,便于测试
        for (MyProcess process : myProcesses) {
            process.setStatus("wait");
        }

        // 打印调度算法名称和时间片大小
        System.out.println("时间片轮转调度算法");
        System.out.println("时间片大小: " + timeSlice);

        // 获取当前时间，用于计算进程的完成时间
        LocalDateTime currentTime = LocalDateTime.now();
        int remainingProcesses = myProcesses.size();

        // 当还有进程处于等待状态时，继续调度
        while (remainingProcesses > 0) {
            // 遍历所有进程，检查是否需要调度
            for (MyProcess process : myProcesses) {
                if (process.getStatus().equals("wait")) {
                    // 当前进程仍需运行
                    if (process.getRemainingTime() > 0) {
                        // 如果进程剩余时间小于等于时间片，则进程可以完成
                        if (process.getRemainingTime() <= timeSlice) {
                            process.setFinishTime(currentTime.plusMinutes(process.getRemainingTime()));
                            process.setRemainingTime(0);
                            process.setStatus("finish");
                            remainingProcesses--;
                        } else {
                            // 如果进程剩余时间大于时间片，则减少时间片长度
                            process.setRemainingTime(process.getRemainingTime() - timeSlice);
                            currentTime.plusMinutes(timeSlice);
                        }

                        // 打印进程当前状态
                        System.out.println("进程名: " + process.getName()
                                + " 提交时间: " + process.getArrivalTime()
                                + " 运行时间: " + process.getBurstTime()
                                + " 开始时间: " + process.getStartTime().format(formatter)
                                + " 完成时间: " + process.getFinishTime().format(formatter)
                                + " 状态: " + process.getStatus());
                    }
                }
            }
        }
    }



}